home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 July / EnigmA AMIGA RUN 20 (1997)(G.R. Edizioni)(IT)[!][issue 1997-07 & 08][EAR-CD IV].iso / earcd / docs / misc / bcplforb.txt < prev    next >
Text File  |  1997-03-28  |  6KB  |  198 lines

  1.                          HOW TO DO A FORBID() IN BCPL
  2.                          ============================
  3.  
  4.                           By !LAiRFiGHT! of fLATLiNE
  5.  
  6. To disable task switching on the Amiga, a normal program written in assembler
  7. would do something like this:
  8.  
  9.         move.l    4.w,a6        ;Get base of exec.library
  10.         jsr    -$84(a6)    ;Call the Forbid() function
  11.  
  12. However, parts of the Amiga operating system (the DOS parts) was, in the 1.x
  13. versions, written in a language called BCPL.  Now let's take a look at how a
  14. Forbid() call was implemented in that language...
  15.  
  16.  
  17.         ;Some other code here...
  18.         ;...
  19.  
  20.         move.l    #-$84,d1    ;Line 1
  21.         moveq    #$20,d0        ;Line 2
  22.         move.l    $160(a2),a4    ;Line 3
  23.         jsr    (a5)        ;Line 4
  24.  
  25.         ;...and continue with no task switching.
  26.  
  27.                                  Explanation:
  28.                                  ------------
  29.  
  30. Line 1        move.l    #-$84,d1
  31.         This is an argument to the internal dos function "ExecCall".
  32.         It is the normal function offset in exec.library (see the
  33.         first example). The internal ExecCall function actually
  34.         takes some more arguments. They are:
  35.             d1    offset in exec.library
  36.             d2    what to put in d0
  37.             d3    what to put in d1
  38.             d4    what to put in a0
  39.         and the stack (the internal BCPL stack that lies in a1 and
  40.         goes upwards) may contain values to put into a1 and a2.
  41.         Anyway, Forbid() dosn't take any arguments so only d1 need
  42.         to be set in this example.
  43.  
  44. Line 2        moveq    #$20,d0
  45.         Wow! It uses moveq! =) Anyway, this means that the internal
  46.         BCPL stack should be increased with $20.
  47.  
  48. Line 3        move.l    $160(a2),a4
  49.         A2 always points to the internal Global Vector Table. This
  50.         table contains addresses to the various functions to be used.
  51.         The address to ExecCall just happens to be at $160, so fetch
  52.         it and place it in a4...
  53.  
  54. Line 4        jsr    (a5)
  55.         ...and jump to A5!?!?
  56.  
  57. No it isn't a typo...  it actually calls a5!  This is because a5 points to the
  58. Function Call Routine (*sigh*), which looks like this:
  59.  
  60.         move.l    (a7)+,a3        ;Line 1
  61.         movem.l    a1/a3-a4,-12(a1,d0.l)    ;Line 2
  62.         adda.l    d0,a1            ;Line 3
  63.         movem.l    d1-d4,(a1)        ;Line 4
  64.         jmp    (a4)            ;Line 5
  65.  
  66.                                  Explanation:
  67.                                  ------------
  68.  
  69. Line 1        move.l    (a7)+,a3
  70.         Get the return address. Ofcourse, a BCPL program would NEVER
  71.         do a normal RTS...
  72.  
  73. Line 2        movem.l    a1/a3-a4,-12(a1,d0.l)
  74.         As mentioned, a1 is the internal stack pointer, and d0 was set
  75.         to a value to increment the stack pointer with. What this line
  76.         does, is to save the old stack pointer, and the return address
  77.         (in a3) and the function address (in a4) just before the
  78.         new stack, so that it can be easily (?) restored later.
  79.  
  80. Line 3        adda.l    d0,a1
  81.         Increment the stack pointer.
  82.  
  83. Line 4        movem.l    d1-d4,(a1)
  84.         Save the arguments to the stack. WHY???
  85.  
  86. Line 5        jmp    (a4)
  87.         Phew!  FINALLY call the Forbid() function.  Or?  Eh..  wait a
  88.         sec...  oh NO!!!?  This isn't Forbid() - This is the *ExecCall*
  89.         routine which will IN TURN call Forbid()!!!!  AAARGH!
  90.  
  91. Hmm.. let's take a look at the ExecCall routine then. It couldn't be THAT
  92. bad, could it?
  93.  
  94.         movem.l    a0-a2/a5-a6,-(a7)    ;Line 1
  95.         move.l    d1,d7            ;Line 2
  96.         move.l    d2,d0            ;Line 3
  97.         move.l    d3,d1            ;Line 4
  98.         move.l    d4,a0            ;Line 5
  99.         move.l    $14(a1),a2        ;Line 6
  100.         move.l    $10(a1),a1        ;Line 7
  101.         move.l    4.w,a6            ;Line 8
  102.         jsr    0(a6,d7.w)        ;Line 9
  103.         movem.l    (a7)+,a0-a2/a5-a6    ;Line 10
  104.         move.l    d0,d1            ;Line 11
  105.         jmp    (a6)            ;Line 12
  106.  
  107.  
  108.                                  Explanation:
  109.                                  ------------
  110.  
  111. Line 1        movem.l    a0-a2/a5-a6,-(a7)
  112.         Hmm.. it uses a7 as a stack pointer?? What a funny idea!!
  113.  
  114. Line 2        move.l    d1,d7
  115.         This is the offset in exec.library to which we will jsr
  116.         later. Place it in d7.
  117.  
  118. Line 3        move.l    d2,d0
  119.         BCPL arguments are always passed in d1, d2, d3 and d4, so
  120.         take the second argument and place it in d0 (as exec (and
  121.         other) routines often take their arguments in the low
  122.         registers, such as d0).
  123.  
  124. Line 4        move.l    d3,d1
  125.         Same thing here...
  126.  
  127. Line 5        move.l    d4,a0
  128.         ...and here... Note that Forbid() doesn't require ANY
  129.         registers to be loaded with ANYTHING...
  130.  
  131. Line 6        move.l    $14(a1),a2
  132.         If it isn't enough with d1, d2, d3 and d4, let's use the
  133.         stack instead... Offset $14 in the internal stack seems to
  134.         contain the argument to put into a2... Note that if the
  135.         main program in rare circumstances actually wants to SET this
  136.         value to something, it isn't just to move it into $14(a1)...
  137.         It has to be moved into $14(a1,d0.l), where d0 contains the
  138.         value to add to the internal stack (as mentioned).
  139.  
  140. Line 7        move.l    $10(a1),a1
  141.         Same thing here. This will also destroy a1 as a stack pointer.
  142.         (This is why it was saved on a7... a7 isn't trashed by
  143.         exec functions.)
  144.  
  145. Line 8        move.l    4.w,a6
  146.         Get the pointer to exec.library.
  147.  
  148. Line 9        jsr    0(a6,d7.w)
  149.         AT LAST!!!!! A call to Forbid()!!! Ta-daaa!!!!
  150.  
  151. Line 10        movem.l    (a7)+,a0-a2/a5-a6
  152.         Restore what we preserved earlier...
  153.  
  154. Line 11        move.l    d0,d1
  155.         Well...  exec.library (along with all the other libraries I
  156.         know of) return their result in d0.  However; BCPL programs
  157.         want their return codes in d1 (why amn't I surprised?) so let's
  158.         just move it...  (NB:  Forbid() doesn't return anything
  159.         useful...)
  160.  
  161. Line 12        jmp    (a6)
  162.         Ehmm... a6??? But I though we put the return address in a3
  163.         a while ago??? Yup, sure did. In BCPL, a6 points to the
  164.         Return From Function Routine, which looks like this:
  165.  
  166.         movem.l    -12(a1),a1/a3    ;Line 1
  167.         move.l    -4(a1),a4    ;Line 2
  168.         jmp    (a3)        ;Line 3
  169.  
  170.                                  Explanation:
  171.                                  ------------
  172.  
  173. Line 1        movem.l    -12(a1),a1/a3
  174.         Get old stackpointer (before we added d0 to it) back. Also
  175.         restore a3 (the return address).
  176.  
  177. Line 2        move.l    -4(a1),a4
  178.         Get a4 from the OLD stack. A4 will now contain the value
  179.         it had even before we changed it to contain the pointer to
  180.         ExecCall. (It contained/contains a pointer to the section
  181.         of code currently running...)
  182.  
  183. Line 3        jmp    (a3)
  184.         ...and voilá! Return to the main program again!
  185.  
  186.  
  187.    Now we just have to go through the same thing again, to do a Permit()...
  188.  
  189.  
  190.  
  191. .-----------------------------------------------------------------------------.
  192. |                   Thanks to Maxwold for the disassembly!                    |
  193. |                                See you all!                                 |
  194. |                           !LAiRFiGHT! of fLATLiNE                           |
  195. `-----------------------------------------------------------------------------'
  196.  
  197. Note: They HAVE changed it in V36... =)
  198.